package com.moon.java.code.analyzer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.alibaba.fastjson2.JSON;


// 定义 MyBatisXMLParser 类，包含主要的解析逻辑
public class MyBatisXMLParser {
    private static final Logger LOGGER = Logger.getLogger(MyBatisXMLParser.class.getName());

    // 解析单个 XML 文件的方法
    public static MapperInfo parseMapperFile(File file) {
        MapperInfo mapperInfo = new MapperInfo();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(file);

            // 获取 mapper 节点的 namespace 属性
            Element root = doc.getDocumentElement();
            mapperInfo.setNamespace(root.getAttribute("namespace"));

            // 处理 resultMap 节点
            processResultMapNodes(doc, mapperInfo);

            // 处理 sql 节点
            processSqlNodes(doc, mapperInfo);

            // 处理 select、update、insert 节点
            processCrudNodes(doc, mapperInfo);

        } catch (ParserConfigurationException | SAXException | IOException e) {
            LOGGER.log(Level.SEVERE, "Error parsing XML file: " + file.getName(), e);
        }
        return mapperInfo;
    }

    // 处理 resultMap 节点
    private static void processResultMapNodes(Document doc, MapperInfo mapperInfo) {
        NodeList resultMapNodes = doc.getElementsByTagName("resultMap");
        for (int i = 0; i < resultMapNodes.getLength(); i++) {
            Element resultMapElement = (Element) resultMapNodes.item(i);
            ResultMapInfo resultMapInfo = new ResultMapInfo();
            resultMapInfo.setType(resultMapElement.getAttribute("type"));

            NodeList resultNodes = resultMapElement.getElementsByTagName("result");
            for (int j = 0; j < resultNodes.getLength(); j++) {
                Element resultElement = (Element) resultNodes.item(j);
                resultMapInfo.getProperties().add(resultElement.getAttribute("property"));
            }
            
            NodeList idNodes = resultMapElement.getElementsByTagName("id");
            for (int j = 0; j < idNodes.getLength(); j++) {
                Element idNode = (Element) idNodes.item(j);
                resultMapInfo.getProperties().add(idNode.getAttribute("property"));
            }
            mapperInfo.getResultMapInfos().add(resultMapInfo);
        }
    }

    // 处理 sql 节点
    private static void processSqlNodes(Document doc, MapperInfo mapperInfo) {
        NodeList sqlNodes = doc.getElementsByTagName("sql");
        for (int i = 0; i < sqlNodes.getLength(); i++) {
            Element sqlElement = (Element) sqlNodes.item(i);
            SqlInfo sqlInfo = new SqlInfo();
            sqlInfo.setId(sqlElement.getAttribute("id"));
            sqlInfo.setContent(sqlElement.getTextContent().trim());
            mapperInfo.getSqlInfos().add(sqlInfo);
        }
    }

    // 处理 select、update、insert 节点
    private static void processCrudNodes(Document doc, MapperInfo mapperInfo) {
        String[] crudTags = { "select", "update", "insert" };
        for (String tag : crudTags) {
            NodeList crudNodes = doc.getElementsByTagName(tag);
            for (int i = 0; i < crudNodes.getLength(); i++) {
                Element crudElement = (Element) crudNodes.item(i);
                mapperInfo.getMethods().add(crudElement.getAttribute("id"));
            }
        }
    }

    // 递归迭代目录，查找所有 XML 文件并解析
    private static Map<String, MapperInfo> iterateDirectory(File directory) {
        Map<String, MapperInfo> mapperInfoMap = new HashMap<>();
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        mapperInfoMap.putAll(iterateDirectory(file));
                    } else if (file.getName().endsWith(".xml")) {
                        MapperInfo mapperInfo = parseMapperFile(file);
                        String namespace = mapperInfo.getNamespace();
                        mapperInfoMap.computeIfAbsent(namespace, k -> new MapperInfo()).merge(mapperInfo);
                    }
                }
            }
        }
        return mapperInfoMap;
    }

    // 解析目录，先检查序列化文件，不存在则解析并序列化
    @SuppressWarnings("unchecked")
    public static Map<String, MapperInfo> parseDirectory(String directoryPath, boolean useCache) {
        File directory = new File(directoryPath);
        String lastDirectoryName = directory.getName();
        File serFile = new File(lastDirectoryName + ".ser");
        Map<String, MapperInfo> mapperInfoMap = null;

        if (useCache && serFile.exists()) {
            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serFile))) {
                mapperInfoMap = (Map<String, MapperInfo>) ois.readObject();
            } catch (IOException | ClassNotFoundException e) {
                LOGGER.log(Level.SEVERE, "Error reading serialized file: " + serFile.getName(), e);
            }
        }

        if (mapperInfoMap == null) {
            mapperInfoMap = iterateDirectory(directory);

            // 过滤 sqlInfos
            mapperInfoMap.values().forEach(MapperInfo::filterSqlInfos);

            try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serFile))) {
                oos.writeObject(mapperInfoMap);
            } catch (IOException e) {
                LOGGER.log(Level.SEVERE, "Error writing serialized file: " + serFile.getName(), e);
            }
        }
        Map<String, MapperInfo> temp=new HashMap<String, MapperInfo>();
        //建立entity mapper映射
        for(Map.Entry<String, MapperInfo> e:mapperInfoMap.entrySet()) {
            MapperInfo mapperInfo=e.getValue();
            mapperInfo.getResultMapInfos().forEach(resultMapInfo->{
                temp.computeIfAbsent(resultMapInfo.getType(), k -> new MapperInfo()).merge(mapperInfo);
            });
        }
        mapperInfoMap.putAll(temp);
        return mapperInfoMap;
    }

    public static void main(String[] args) {
        String directoryPath = "D:\\git\\ecej-pay-task\\src\\main\\resources\\mybatis";
        boolean useCache = true; // 可以根据需要修改该值
        Map<String, MapperInfo> mapperInfoMap = parseDirectory(directoryPath, useCache);
        String jsonResult = JSON.toJSONString(mapperInfoMap);
        System.out.println(jsonResult);
    }
    
 // 定义 ResultMapInfo 类，用于存储 resultMap 相关信息
    public static class ResultMapInfo implements Serializable {
        private static final long serialVersionUID = 1L;
        private String type;
        private Set<String> properties = new HashSet<>();

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = extractLastClassName(type);
        }

        public Set<String> getProperties() {
            return properties;
        }

        public void setProperties(Set<String> properties) {
            this.properties = properties;
        }

        // 提取类全路径名的最后一级类名
        private String extractLastClassName(String fullClassName) {
            int lastDotIndex = fullClassName.lastIndexOf('.');
            return lastDotIndex != -1 ? fullClassName.substring(lastDotIndex + 1) : fullClassName;
        }
    }

    // 定义 SqlInfo 类，用于存储 sql 节点信息
    public static class SqlInfo implements Serializable {
        private static final long serialVersionUID = 1L;
        private String id;
        private String content;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content.replaceAll("\\s+", "");
        }
    }

    // 定义 MapperInfo 类，用于存储 mapper 节点相关信息
    public static class MapperInfo implements Serializable {
        private static final long serialVersionUID = 1L;
        private String namespace;
        private List<ResultMapInfo> resultMapInfos = new ArrayList<>();
        private List<SqlInfo> sqlInfos = new ArrayList<>();
        private Set<String> methods = new HashSet<>();

        public String getNamespace() {
            return namespace;
        }

        public void setNamespace(String namespace) {
            this.namespace = extractLastClassName(namespace);
        }

        public List<ResultMapInfo> getResultMapInfos() {
            return resultMapInfos;
        }

        public void setResultMapInfos(List<ResultMapInfo> resultMapInfos) {
            this.resultMapInfos = resultMapInfos;
        }

        public List<SqlInfo> getSqlInfos() {
            return sqlInfos;
        }

        public void setSqlInfos(List<SqlInfo> sqlInfos) {
            this.sqlInfos = sqlInfos;
        }

        public Set<String> getMethods() {
            return methods;
        }

        public void setMethods(Set<String> methods) {
            this.methods = methods;
        }

        // 合并相同 namespace 的 MapperInfo 数据
        public void merge(MapperInfo other) {
            this.resultMapInfos.addAll(other.resultMapInfos);
            this.sqlInfos.addAll(other.sqlInfos);
            this.methods.addAll(other.methods);
        }

        // 过滤 sqlInfos，只保留 id 包含 "column"（不区分大小写）的记录
        public void filterSqlInfos() {
            sqlInfos.removeIf(sqlInfo -> !sqlInfo.getId().toLowerCase().contains("column"));
        }

        // 提取类全路径名的最后一级类名
        private String extractLastClassName(String fullClassName) {
            int lastDotIndex = fullClassName.lastIndexOf('.');
            return lastDotIndex != -1 ? fullClassName.substring(lastDotIndex + 1) : fullClassName;
        }
    }
}
